package com.example.test15middleware.config;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.redisson.api.RLock;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
public class TicketNoGenerator {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedissonService redissonService;

    private String date = "";

    private static Integer count = 1;

    /**
     * 一天最多生成100成工单号，足够了
     */
    private static final String STR_FORMAT = "000000";
    private static final int MAX_COUNT = 1000000;

    /**
     * 工单号生成
     */
    public String generateTicketNo() {
        return generateNo(OutWorkConstant.KEY_TICKET_NO);
    }

    /**
     * 生成申请编号
     *
     * @return String 申请编号
     */
    public String generateApplicationNo() {
        return generateNo(OutWorkConstant.KEY_APPLICATION_NO);
    }

    /**
     * 生成 key 编号
     * 格式yyyyMMdd+数量
     *
     * @param key 编号标识
     * @return java.lang.String
     */
    private String generateNo(String key) {
        String redisLockKey = OutWorkConstant.OUTWORK + OutWorkConstant.REDIS_NO_LOCK + key;
        String redisCountKey = OutWorkConstant.OUTWORK + OutWorkConstant.REDIS_COUNT_KEY + key;
        RLock lock = null;
        try {
            lock = redissonService.lock(redisLockKey, TimeUnit.MILLISECONDS, 10);

            setDateAndCount(redisCountKey);

            return this.date + formatInt(count % MAX_COUNT);
        } finally {
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.forceUnlock();
            }
        }
    }

    private String formatInt(Integer value) {
        DecimalFormat df = new DecimalFormat(STR_FORMAT);
        return df.format(value);
    }

    private void setDateAndCount(String redisCountKey) {
        //每次从redis中取上次的值，多个人同时启动时。
        String countInRedis = stringRedisTemplate.opsForValue().get(redisCountKey);
        if (StringUtils.isNotBlank(countInRedis) && countInRedis.contains(":")) {
            date = countInRedis.split(":")[0];
            count = Integer.parseInt(countInRedis.split(":")[1]);
        }

        if (count >= MAX_COUNT) {
            throw new RuntimeException("当日的工单号已经使用完");
        }

        String newDate = DateFormatUtils.format(new Date(), "yyyyMMdd");
        if (date.equals(newDate)) {
            count += 1;
        } else {
            this.date = newDate;
            //从1开始
            count = 1;
        }

        stringRedisTemplate.opsForValue().set(redisCountKey, this.date + ":" + count);
    }

    /**
     * 重设Redis中 redisCountKey 的编号为 no
     *
     * @param redisCountKey 要重置编号key
     * @param no            最大编号
     */
    public void resetNo(String redisCountKey, String no) {
        //最大数量的长度
        int maxCountLength = String.valueOf(MAX_COUNT - 1).length();
        if (StringUtils.isNotBlank(no) && no.length() >= maxCountLength) {
            int length = no.length();
            //截取数量
            String currentCount = no.substring(length - maxCountLength, length);
            //重置数量
            resetDateAndCount(redisCountKey, Integer.parseInt(currentCount));
        }
    }

    /**
     * 重设 redisCountKey 的数据量为 newCount
     *
     * @param redisCountKey 要重置数量的key
     * @param newCount      重新设置的数量
     * @author zhangzg
     * @date 2021/11/22 14:48
     */
    private void resetDateAndCount(String redisCountKey, int newCount) {
        if (newCount >= MAX_COUNT) {
            throw new RuntimeException("设置的编号超出" + MAX_COUNT);
        }
        this.date = DateFormatUtils.format(new Date(), "yyyyMMdd");
        stringRedisTemplate.opsForValue().set(redisCountKey, this.date + ":" + newCount);
    }

}
